package com.cl.advice;

import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.codehaus.jackson.JsonGenerationException;
import org.codehaus.jackson.map.JsonMappingException;
import org.codehaus.jackson.map.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import com.cl.dao.CommonDao;
import com.cl.dao.SearchDao;
import com.cl.entity.CcPay;
import com.cl.entity.common.DBObject;
import com.cl.service.PayCaculateService;
import com.cl.util.CommonUtil;

@Component
@Aspect 
public class AdvicePay {

	private final static Log log = LogFactory.getLog(AdvicePay.class);
    @Autowired
    private CommonUtil commonUtil;
	@Autowired
	private CommonDao commonDao;
	
	@Autowired
	private SearchDao searchDao;

	@Autowired
	private PayCaculateService payCaculateService;
	
	@Value("#{applicationProperties['PAY_CACULATE_CLASSES']}")
	private String PAY_CACULATE_CLASSES;
	
	//配置切入点,该方法无方法体,主要为方便同类中其他方法使用此处配置的切入点
	@Pointcut("execution(* com.cl.service.CommonService.updateEntity(..))")
	public void aspect(){	}
	@Pointcut("execution(* com.cl.service.CommonService.getEntity(..))")
	public void aspectGet(){	}

	@Pointcut("execution(* com.cl.dao.CommonDao.deleteDBObject(..))")
	public void aspectDelete(){	}
	
	@AfterReturning(pointcut="aspectDelete() && args(entity, description, userId,ip)")
	public void afterReturnDelete(JoinPoint point, DBObject entity, String description, String userId, String ip){		
		String entityName = entity.getClass().getName();
		resetPayCache(entityName);
		
		if(PAY_CACULATE_CLASSES.contains(entityName+","))
			deleteRelPays(entityName.substring((entityName.lastIndexOf(".")+1)),
				entity.getPrimaryId(),userId,ip);
	}
	/*
	 * 配置前置通知,使用在方法aspect()上注册的切入点
	 * 同时接受JoinPoint切入点对象,可以没有该参数
	 */
	@Before("aspect()")
	public void before(JoinPoint point){
		if(log.isInfoEnabled()){
			log.info("before " + point);
		}
		Object[] args = point.getArgs();
		@SuppressWarnings("unchecked")
		HashMap<String, Object> pm = (HashMap<String, Object>)args[1];
		String cn=(String)args[0].toString();
		if(cn.equals("CcPay")){
			Date dt = new Date();
			if(pm.get("rewardFlag")!=null){
				pm.put("rewardCTime", dt);
				pm.put("rewardCMan", commonUtil.getCurrentUserID());
			}else if(pm.get("reEditorCFlag")!=null){
				pm.put("reEditorCTime", dt);
				pm.put("reEditorCMan", commonUtil.getCurrentUserID());
			}
		}
		log.info(args[0]);
	}
	
	//配置后置通知,使用在方法aspect()上注册的切入点
	/*@After("aspect()")
	public void after(JoinPoint joinPoint){
		if(log.isInfoEnabled()){
			log.info("after " + joinPoint);
		}
	}*/
	
	private void deleteRelPays(String entity, Object id, String userId, String ip)
	{
		try {
			ObjectMapper objectMapper = new ObjectMapper();
			// 删除未发放稿酬
			List<CcPay> pays = searchDao.getRelPays(entity, id);
			if ((pays != null) && (pays.size() > 0)) {
				for (int j = 0; j < pays.size(); j++) {
					commonDao.deleteDBObject(pays.get(j), 
							objectMapper.writeValueAsString(pays.get(j)), userId, ip);
				}
			}
		} catch (JsonGenerationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (JsonMappingException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	//c4w reset Cache when data is dirty
	private void resetPayCache(String entityName){
		if(entityName.equals("BasePayfactor") || entityName.equals("com.cl.entity.BasePayfactor")){
			payCaculateService.resetBasePayfactor();
		}else if(entityName.equals("UWhite") || entityName.equals("com.cl.entity.UWhite")){
			payCaculateService.resetWhiteMap();
		}
	}
	
	@AfterReturning(pointcut="aspect() && args(entityName, request, ip)",
			returning="entity")
	public void afterReturn(JoinPoint point, Object entity, 
			String entityName, Map<String,Object> request, String ip)
	{
		if(log.isInfoEnabled()){
			log.info("after " + point);
		}
		//c4w 置缓存无效
		resetPayCache(entityName);
		DBObject e = (DBObject) entity;
		//对历史数据不再重新计算稿酬
		if((Long)e.getPrimaryId()<1000000)
			return;
		
		//更新时对部分实体对应更新稿酬表
		if(PAY_CACULATE_CLASSES.contains(entityName+",")){
			commonDao.updatePays(e, commonUtil.getCurrentUserID(), ip);
		}
		log.info("update pays for "+entityName+":"+e.getPrimaryId());
	}
	
	@AfterReturning(pointcut="aspectGet() && args(entityName,kval,ip)",
			returning="obj")
	public void afterReturnGet(Object obj, String entityName, Object kval, String ip)
	{
		if(kval==null){
			if (PAY_CACULATE_CLASSES.contains(entityName+",")) {
				commonDao.savePays((DBObject) obj, commonUtil.getCurrentUserID(), ip);
			}
			log.info("create pays for "+entityName+":"+kval);
		}
	}
	
}